﻿namespace BadHabit.Factory
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Deployment.Application;
    using System.Globalization;
    using System.Net;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Markup;
    using BadHabit.Factory.Windows.Properties;

    /// <summary>
    /// The main application.
    /// </summary>
    public partial class Client : Application
    {
        public enum TaskViewModes
        {
            POSTIT,
            LISTVIEW
        }

        public static readonly string IDLE_TASK_UID = new System.Guid().ToString();
        public static readonly string APPLICATION_LOGNAME = "Scrum Factory";

        public static Views.TaskSelector TaskSelector
        {
            get;
            private set;
        }

        public static BadHabit.Factory.Windows.FactoryService.ProjectService Service
        {
            get;
            private set;
        }

        public static string[] ClientList
        {
            get;
            private set;
        }

        private static bool threadSetted = false;

        public static Data.TeamDataSet TeamMemberDataSet
        {
            get;
            private set;
        }

        public static Data.TaskDataSet.AverageHoursBySizeItemTypeDataTable AverageHoursBySizeItemType
        {
            get;
            private set;
        }

        public static Data.ProjectDataSet BacklogItemSizes
        {
            get;
            private set;
        }

        /// <summary>
        /// Application constructor.
        /// We want only one instance of this running.
        /// </summary>
        public Client()
            : base()
        {
            InitializeComponent();
            ShutdownMode = ShutdownMode.OnLastWindowClose;
            SetFrameworkElementToUserCulture();
            this.SessionEnding += new SessionEndingCancelEventHandler(this.Client_SessionEnding);

            BadHabit.WPFTools.Converters.LocalizeConverter.ResourceManager = global::BadHabit.Factory.Windows.Properties.Resources.ResourceManager;
        }

        public static string ClientVersion
        {
            get
            {
                string version = global::BadHabit.Factory.Windows.Properties.Resources.Version;
                if (ApplicationDeployment.IsNetworkDeployed)
                {
                    version = version + " (" + ApplicationDeployment.CurrentDeployment.CurrentVersion + ")";
                }
                else
                {
                    version = version + " (DEV VERSION)";
                }

                return version;
            }
        }

        /// <summary>
        /// Commit hours when the user log of oe shutdown the system.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Client_SessionEnding(object sender, SessionEndingCancelEventArgs e)
        {
            if (TaskSelector.CurrentTask != null)
            {
                CommitWorkedTime(TaskSelector.CurrentTask.TaskUId, TaskSelector.CurrentTask.TaskName, TaskSelector.CurrentTaskWorkedTime, false, null);
            }
        }

        /// <summary>
        /// Gets the application main window casted to the BadHabit.Factory.Windows.Main class.
        /// </summary>                        
        public static Views.Main FactoryMainWindow
        {
            get
            {
                return Current.MainWindow as Views.Main;
            }
        }

        /// <summary>
        /// Gets the current application casted to the Factory.App class.
        /// </summary>
        public static Client CurrentClient
        {
            get
            {
                return Client.Current as Client;
            }
        }

        /// <summary>
        /// Show the main window loading the project with the given project number.
        /// <param name="projectNumber">The project number</param>
        /// </summary>        
        public static void ShowMainWindow(int projectNumber)
        {
            Data.ProjectDataSet project = Client.RetriveProject(projectNumber);
            FactoryMainWindow.Refresh(project);
            FactoryMainWindow.projectListBox.listBox.SelectedItem = null;
            ShowMainWindow();
        }

        /// <summary>
        /// Shows the Main Window.
        /// </summary>
        public static void ShowMainWindow()
        {
            // it takes a long time sometimes to refresh..dont now why..so i comment this
            ////Client.FactoryMainWindow.Refresh(); 
            Client.FactoryMainWindow.Show();
            Client.FactoryMainWindow.IsMaximized = true;
            Client.FactoryMainWindow.BringIntoView();
            Client.FactoryMainWindow.Activate();
        }

        /// <summary>
        /// Sets the Culture to the current user culture.
        /// </summary>        
        private static void SetFrameworkElementToUserCulture()
        {
            FrameworkElement.LanguageProperty.OverrideMetadata(
                typeof(FrameworkElement),
                new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentUICulture.IetfLanguageTag)));

            ////System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us");
        }

        /// <summary>
        /// Gets the current client user principal.
        /// </summary>
        public static System.Security.Principal.IPrincipal User
        {
            get
            {
                return BadHabit.WPFTools.RoleChecker.ThreadPrincipal;
            }
        }

        /// <summary>
        /// Returns true if the user has a given role.
        /// </summary>
        /// <param name="role">The role</param>
        /// <returns>True if uesre is in role</returns>
        public static bool UserIsInRole(TeamRoles role)
        {
            if (User == null)
            {
                return false;
            }

            string roleString = role.ToString();
            return User.IsInRole(roleString);
        }

        /// <summary>
        /// Gets the server url.
        /// </summary>
        public static string ServiceServerUrl
        {
            get
            {
                if (!IsConnected)
                {
                    return null;
                }

                return Service.Url.Substring(0, Service.Url.LastIndexOf("/"));
            }
        }

        /// <summary>
        /// Commits the worked time to the server.
        /// </summary>
        /// <param name="taskUId">The task UId</param>
        /// <param name="taskName">The name of the task</param>
        /// <param name="time">The time to be commited</param>
        /// <param name="closeTask">True to close the task</param>
        public static bool CommitWorkedTime(string taskUId, string taskName, System.TimeSpan time, bool closeTask, string newTaskUId)
        {
            string message = string.Empty;
            try
            {
                Service.ChangeTask(taskUId, time.TotalHours, closeTask, newTaskUId);
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_COMMIT_WORKED_HOURS);
                BadHabit.Factory.Views.Error.ShowAlert(string.Format(global::BadHabit.Factory.Windows.Properties.Resources.You_have_already_worked_N_minutes_at_task_TASK, System.Math.Round(time.TotalMinutes, 1), taskName));

                return false;
            }

            return true;
        }

        /// <summary>
        /// Starts the application.
        /// </summary>
        public static void StartApplication()
        {
            StartApplication(true);
        }

        /// <summary>
        /// Starts the application.
        /// </summary>
        public static void StartApplication(bool tryToconnect)
        {
            // Creates the notify icon
            CreateNotifyIcon();

            // Creates the Main Window
            Current.MainWindow = new BadHabit.Factory.Views.Main();

            // Creates the Task Selector Window
            TaskSelector = new BadHabit.Factory.Views.TaskSelector();

            Service = new BadHabit.Factory.Windows.FactoryService.ProjectService();

            // Connets to the server
            if (tryToconnect)
            {
                Connect(true);
            }
        }

        private static void SetProxy()
        {
            // try to auto configure proxy settings
            try
            {
                Microsoft.Win32.RegistryKey internetSettingsKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings");
                string proxyServer = internetSettingsKey.GetValue("ProxyServer") as string;
                string proxyOverride = internetSettingsKey.GetValue("ProxyOverride") as string;
                bool bypassLocal = "<local>".Equals(proxyOverride);
                Service.Proxy = new WebProxy(proxyServer, bypassLocal, null, System.Net.CredentialCache.DefaultCredentials);
            }
            catch
            {
            }
        }

        /// <summary>
        /// Setups the Factory services.
        /// </summary>
        public static bool SetUpService()
        {
            Service = new BadHabit.Factory.Windows.FactoryService.ProjectService();
            Service.Credentials = System.Net.CredentialCache.DefaultCredentials;
            Service.Proxy = null;

            try
            {
                Service.Url = FormatedServiceUrl;
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(
                    ex,
                    global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_CONNECT_TO_SERVER,
                    global::BadHabit.Factory.Windows.Properties.Resources.Your_service_url_is_not_valid);

                return false;
            }

            return true;
        }

        private static string FormatedServiceUrl
        {
            get
            {
                if (Settings.Default.ProjectWebServiceURL.ToUpper().EndsWith("PROJECTSERVICE.ASMX"))
                {
                    return Settings.Default.ProjectWebServiceURL;
                }
                else
                {
                    return Settings.Default.ProjectWebServiceURL + "/ProjectService.asmx";
                }
            }
        }

        /// <summary>
        /// Connect the user to the service.
        /// <param name="fullLoad">When true, besides connect to the server, also loads the project, tasks, members, clients etc..</param>
        /// </summary>
        public static void Connect(bool fullLoad)
        {
            IsConnected = false;

            // clear all th users roles            
            System.Security.Principal.GenericPrincipal p = null;
            notifyIcon.Icon = global::BadHabit.Factory.Windows.Properties.Resources.factoryDisconnected;

            // setups the webservice
            if (!SetUpService())
            {
                return;
            }

            // retrives to reach the service
            // if fails, try to use a proxy
            string memberName = null;
            try
            {
                memberName = Service.CurrentTeamMember();
            }
            catch
            {
                SetProxy();
                try
                {
                    memberName = Service.CurrentTeamMember();
                }
                catch (Exception ex)
                {
                    BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_CONNECT_TO_SERVER);
                    return;
                }
            }

            // retrives the user roles            
            string[] roles = null;
            try
            {
                roles = Service.RetriveTeamMemberRoles();
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_CONNECT_TO_SERVER);
                return;
            }

            // put the roles at the threads principal            
            p = new System.Security.Principal.GenericPrincipal(
                new System.Security.Principal.GenericIdentity(memberName), roles);
            System.Threading.Thread.CurrentPrincipal = p;

            // this is a WPF workaround....
            // this can be called only once
            if (!threadSetted)
            {
                AppDomain.CurrentDomain.SetThreadPrincipal(System.Threading.Thread.CurrentPrincipal);
                threadSetted = true;
            }

            // sets the UI role checker
            BadHabit.WPFTools.RoleChecker.ThreadPrincipal = p;

            IsConnected = true;

            if (roles.Length == 0)
            {
                BadHabit.Factory.Views.Error.ShowAlert(
                    String.Format(global::BadHabit.Factory.Windows.Properties.Resources.User_with_no_roles, memberName));
                return;
            }

            // if everything went ok, and need to bind all
            if (fullLoad)
            {
                FullLoad();
            }
        }

        /// <summary>
        /// Loads the initial data required for the application, such as Projects, Tasks, Clients etc..
        /// </summary>
        private static void FullLoad()
        {
            Client.FactoryMainWindow.ConnectedStatus = IsConnected;

            // Load the Team Members
            LoadTeamMembers();

            // Load the Clients
            LoadClientList();

            LoadAverageHoursBySizeItemType();

            // Load backlog Item sizes
            LoadBacklogItemSizes();

            // Load project Models
            LoadProjectModels();

            // Load project Plataforms
            LoadProjectPlataforms();

            // Load project Categories
            LoadProjectCategories();

            LoadProposalTemplateList();

            // Load the factory velocity
            LoadFactoryVelocity();

            LoadFactorySourceControlViewUrl();

            // AND FINNALLY..AND IT MUST BE AT THE END

            // Binds project
            Client.FactoryMainWindow.Bind();

            // Binds the user tasks
            TaskSelector.Bind();
        }

        public static double TeamVelocity { get; private set; }

        #region Load Data Methods
        private static void LoadFactorySourceControlViewUrl()
        {
            try
            {
                SourceControlViewUrl = Service.RetriveSourceControlViewUrl();
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_SOURCECONTROL_URL);
            }
        }

        /// <summary>
        /// Loads the factory velocity and sets it at the maisn window title bar.
        /// </summary>
        private static void LoadFactoryVelocity()
        {
            TeamVelocity = 0;
            try
            {
                TeamVelocity = Service.RetriveFactoryTeamVelocity();
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_TEAM_VELOCITY);
            }

            BadHabit.Factory.Converters.VelocityIsHigherConverter.MaxVelocity = TeamVelocity;

            Client.FactoryMainWindow.factoryVelocityTextBlock.Text = TeamVelocity.ToString("F1");
        }

        /// <summary>
        /// Loads the client list to the application.
        /// </summary>
        private static void LoadClientList()
        {
            string[] list = new string[0];
            try
            {
                list = Service.RetriveAllClients();
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_CLIENTS);
            }

            List<string> sortedList = new List<string>(list);
            sortedList.Sort();
            ClientList = sortedList.ToArray();

            ((ObjectDataProvider)Client.Current.Resources["ClientList"]).ObjectInstance = ClientList;
        }

        /// <summary>
        /// Loads the team members to the application.
        /// </summary>
        private static void LoadTeamMembers()
        {
            TeamMemberDataSet = new BadHabit.Factory.Data.TeamDataSet();
            try
            {
                TeamMemberDataSet.Merge(Service.RetriveAllTeamMembers());
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_TEAM_MEMBERS);
            }

            SetTeamMembersImageUri();

            System.Data.DataView activeView = TeamMemberDataSet.DefaultViewManager.CreateDataView(TeamMemberDataSet.Member);
            activeView.Sort = "NickName";
            activeView.RowFilter = "Disable <> 1 or Disable is null";
            ((ObjectDataProvider)Client.Current.Resources["ActiveTeamMemberList"]).ObjectInstance = activeView;
        }

        private static void SetTeamMembersImageUri()
        {
            if (!TeamMemberDataSet.Member.Columns.Contains("ImageUri"))
            {
                TeamMemberDataSet.Member.Columns.Add("ImageUri", typeof(string));
            }

            foreach (Data.TeamDataSet.MemberRow memberRow in TeamMemberDataSet.Member.Rows)
            {
                memberRow["ImageUri"] = CreateMemberImageUri(memberRow.MemberId);
            }
        }

        public static string CreateMemberImageUri(string memberId)
        {
            return Client.ServiceServerUrl + "/MemberImage.aspx?memberId=" + memberId + "&" + DateTime.Now.Ticks;
        }

        /// <summary>
        /// Loads backlog item sizes at the application resource BacklogItemSizeList.        
        /// </summary>
        private static void LoadBacklogItemSizes()
        {
            BacklogItemSizes = new BadHabit.Factory.Data.ProjectDataSet();
            try
            {
                BacklogItemSizes.Merge(Service.RetriveBacklogItemSizes());
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_BACKLOG_SIZES);
                return;
            }

            BindingListCollectionView view = (BindingListCollectionView)CollectionViewSource.GetDefaultView(BacklogItemSizes.SizeType);
            view.SortDescriptions.Add(new SortDescription("OrganizationArea", ListSortDirection.Ascending));
            view.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
            view.SortDescriptions.Add(new SortDescription("Description", ListSortDirection.Ascending));
            view.GroupDescriptions.Add(new PropertyGroupDescription("OrganizationArea"));

            ((ObjectDataProvider)Client.Current.Resources["BacklogItemSizeList"]).ObjectInstance = view;
        }

        /// <summary>
        /// Loads backlog item sizes at the application resource BacklogItemSizeList.        
        /// </summary>
        private static void LoadAverageHoursBySizeItemType()
        {
            Data.TaskDataSet task = new BadHabit.Factory.Data.TaskDataSet();
            try
            {
                task.Merge(Service.RetriveAverageHoursBySizeItemType());
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_AVERAGE_BY_SIZE);
                return;
            }

            AverageHoursBySizeItemType = task.AverageHoursBySizeItemType;
        }

        /// <summary>
        /// Loads project models at the application resource ProjectModelList.
        /// </summary>
        private static void LoadProjectModels()
        {
            Data.ProjectDataSet ds = new Data.ProjectDataSet();
            try
            {
                ds.Merge(Service.RetriveAllProjectModels());
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_PROJECT_MODELS);
            }

            System.Data.DataView view = ds.ProjectModel.DefaultView;
            view.Sort = "Model";
            ((ObjectDataProvider)Client.Current.Resources["ProjectModelList"]).ObjectInstance = view;
        }

        /// <summary>
        /// Loads project plataform at the application resource ProjectPlataformList.
        /// </summary>
        private static void LoadProjectPlataforms()
        {
            Data.ProjectDataSet ds = new Data.ProjectDataSet();
            try
            {
                ds.Merge(Service.RetriveAllProjectPlataforms());
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_PROJECT_PLATAFORMS);
            }

            System.Data.DataView view = ds.ProjectPlataform.DefaultView;
            view.Sort = "Plataform";
            ((ObjectDataProvider)Client.Current.Resources["ProjectPlataformList"]).ObjectInstance = view;
        }

        /// <summary>
        /// Loads project plataform at the application resource ProjectCategoryList.
        /// </summary>
        private static void LoadProjectCategories()
        {
            string[] categories = new string[0];
            try
            {
                categories = Service.RetriveProjectTemplateList();
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_PROJECT_CATEGORIES);
            }

            ((ObjectDataProvider)Client.Current.Resources["ProjectCategoryList"]).ObjectInstance = categories;
        }

        /// <summary>
        /// Loads proposal template
        /// </summary>
        private static void LoadProposalTemplateList()
        {
            if (!UserIsInRole(TeamRoles.COMMERCIAL_GUY))
            {
                return;
            }

            string[] templateList = new string[0];
            try
            {
                templateList = Service.RetriveProposalTemplateList();
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_PROPOSAL_MODEL_LIST);
            }

            ((ObjectDataProvider)Client.Current.Resources["ProposalTemplateList"]).ObjectInstance = templateList;
        }
        #endregion

        #region Retrive Methods
        /// <summary>
        /// Retrive project product owners.
        /// </summary>
        /// <param name="projectUId">The project UId</param>
        /// <returns>The backlogitem unit table</returns>
        public static System.Data.DataView RetriveProjectProductOwners(string companyName)
        {
            Data.TeamDataSet team = new BadHabit.Factory.Data.TeamDataSet();
            try
            {
                team.Merge(Service.RetriveMembersByCompany(companyName));
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_CLIENTS);
            }

            System.Data.DataView view = team.Member.DefaultView;
            view.Sort = "NickName";

            return view;
        }

        public static Data.ProjectDataSet RetriveProjectAndRolesOnly(string projectUId)
        {
            Data.ProjectDataSet project = new BadHabit.Factory.Data.ProjectDataSet();
            try
            {
                project.Merge(Client.Service.RetriveProjectAndRolesOnly(projectUId));
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_PROJECT);
            }

            return project;
        }

        public static Data.ProjectDataSet RetriveProject(string projectUId)
        {
            Data.ProjectDataSet project = new BadHabit.Factory.Data.ProjectDataSet();
            try
            {
                project.Merge(Client.Service.RetriveProject(projectUId));
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_PROJECT);
            }

            return project;
        }

        public static Data.ProjectDataSet RetriveProject(int projectNumber)
        {
            Data.ProjectDataSet project = new BadHabit.Factory.Data.ProjectDataSet();
            try
            {
                project.Merge(Client.Service.RetriveProjectByNumber(projectNumber));
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, String.Format(global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_PROJECT_N, projectNumber));
            }

            return project;
        }
        #endregion

        public static void LoadBacklogUnits()
        {
            if (!Client.IsConnected)
            {
                return;
            }

            Data.ProjectDataSet project = new BadHabit.Factory.Data.ProjectDataSet();
            project.EnforceConstraints = false;
            try
            {
                project.Merge(Client.Service.RetriveBacklogItemUnits());
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_BACKLOGITEMUNITS);
            }

            ObjectDataProvider ob = Current.Resources["GenericUnitList"] as ObjectDataProvider;
            project.BacklogItemUnit.DefaultView.Sort = "UnitName";
            ob.ObjectInstance = project.BacklogItemUnit.DefaultView;
        }

        /// <summary>
        /// Ends the application.
        /// </summary>
        public static void EndApplication()
        {
            // commites the time
            if (TaskSelector.CurrentTask != null)
            {
                CommitWorkedTime(TaskSelector.CurrentTask.TaskUId, TaskSelector.CurrentTask.TaskName, TaskSelector.CurrentTaskWorkedTime, false, null);
            }

            // save the configuration
            global::BadHabit.Factory.Windows.Properties.Settings.Default.Save();

            // shut id down
            Client.Current.Shutdown();
        }

        private static bool isConnected = false;

        /// <summary>
        /// Gets and Sets the client connection state.
        /// </summary>
        public static bool IsConnected
        {
            get
            {
                return isConnected;
            }

            private set
            {
                isConnected = value;
                if (value)
                {
                    notifyIcon.Icon = global::BadHabit.Factory.Windows.Properties.Resources.factoryConnected;
                    Factory.Client.FactoryMainWindow.tabControl.IsEnabled = true;
                    Factory.Client.FactoryMainWindow.projectListBox.IsEnabled = true;
                }
                else
                {
                    notifyIcon.Icon = global::BadHabit.Factory.Windows.Properties.Resources.factoryDisconnected;
                    Factory.Client.FactoryMainWindow.tabControl.IsEnabled = false;
                    Factory.Client.FactoryMainWindow.projectListBox.IsEnabled = false;
                }
            }
        }

        /// <summary>
        /// Saves a given project.
        /// </summary>
        /// <param name="project">The project to be saved</param>
        public static bool SaveProject(Data.ProjectDataSet project)
        {
            string alert = null;

            try
            {
                project.Project[0].ValidateToSave();
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowAlert(ex.Message);
                return false;
            }

            project.Project[0].AcceptPlannedItems();

            BadHabit.Factory.Windows.FactoryService.ProjectDataSet savedProject = null;
            try
            {
                savedProject = Service.SaveProject(ConvertToProxyProjectDataSet(project.GetChanges()), out alert);
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_SAVE_PROJECT);
                return false;
            }

            if (alert != null)
            {
                string locAlert = (string)global::BadHabit.Factory.Windows.Properties.Resources.ResourceManager.GetObject(alert);
                if (locAlert == null)
                {
                    locAlert = alert;
                }

                BadHabit.Factory.Views.Error.ShowAlert(locAlert);
                return false;
            }

            if (savedProject != null)
            {
                project.Merge(savedProject);
                if (savedProject.Project.Count > 0)
                {
                    UpdateSelectedProject(savedProject.Project[0]);
                }
            }

            return true;
        }

        public static void UpdateSelectedProject(BadHabit.Factory.Windows.FactoryService.ProjectDataSet.ProjectRow updatedProject)
        {
            if (FactoryMainWindow.projectListBox.SelectedProject == null)
            {
                return;
            }

            if (!FactoryMainWindow.projectListBox.SelectedProject.ProjectUId.Equals(updatedProject.ProjectUId))
            {
                return;
            }

            FactoryMainWindow.projectListBox.SelectedProject.ItemArray = updatedProject.ItemArray;
        }

        public static bool SaveTasks(Data.TaskDataSet.TaskDataTable tasks)
        {
            string alert = null;
            BadHabit.Factory.Windows.FactoryService.TaskDataSet savedTasks = null;
            System.Data.DataSet taskChanged = tasks.DataSet.GetChanges();
            if (taskChanged == null)
            {
                return true;
            }

            try
            {
                savedTasks = Service.SaveTask(ConvertToProxyTaskDataSet(taskChanged), out alert);
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_SAVE_TASK);
                return false;
            }

            if (alert != null)
            {
                BadHabit.Factory.Views.Error.ShowAlert(alert);
                return false;
            }

            if (savedTasks != null)
            {
                tasks.Merge(savedTasks.Task);
            }

            // after saved, refresh things
            Client.FactoryMainWindow.effortBar.Refresh();
            Client.TaskSelector.Bind();

            return true;
        }

        /// <summary>
        /// Converts a DataSet to the proxy version of the Task DataSet.
        /// </summary>
        /// <param name="task">the task to be converted</param>
        /// <returns>The proxy task dataset</returns>
        public static BadHabit.Factory.Windows.FactoryService.TaskDataSet ConvertToProxyTaskDataSet(System.Data.DataSet tasks)
        {
            BadHabit.Factory.Windows.FactoryService.TaskDataSet data = new BadHabit.Factory.Windows.FactoryService.TaskDataSet();
            data.EnforceConstraints = false;
            data.Merge(tasks);
            return data;
        }

        /// <summary>
        /// Converts a DataSet to the proxy version of the Project DataSet.
        /// </summary>
        /// <param name="project">the project t be converted</param>
        /// <returns>The proxy project dataset</returns>
        public static BadHabit.Factory.Windows.FactoryService.ProjectDataSet ConvertToProxyProjectDataSet(System.Data.DataSet project)
        {
            BadHabit.Factory.Windows.FactoryService.ProjectDataSet data = new BadHabit.Factory.Windows.FactoryService.ProjectDataSet();
            data.EnforceConstraints = false;
            data.Merge(project, true);
            return data;
        }

        /// <summary>
        /// Converts a DataSet to the proxy version of the Team DataSet.
        /// </summary>
        /// <param name="teamDataSet">the dataset to be converted</param>
        /// <returns>The proxy project dataset</returns>
        public static BadHabit.Factory.Windows.FactoryService.TeamDataSet ConvertToProxyTeamDataSet(System.Data.DataSet teamDataSet)
        {
            BadHabit.Factory.Windows.FactoryService.TeamDataSet data = new BadHabit.Factory.Windows.FactoryService.TeamDataSet();
            data.EnforceConstraints = false;
            data.Merge(teamDataSet, true);
            return data;
        }

        public static Data.ProjectDataSet CreateNewProject()
        {
            ObjectDataProvider o = Client.Current.Resources["ProjectCategoryList"] as ObjectDataProvider;
            if (o == null || o.ObjectInstance == null)
            {
                return null;
            }

            string[] categories = (string[])o.ObjectInstance;

            if (categories.Length == 0)
            {
                return null;
            }

            return CreateNewProject(categories[0]);
        }

        public static Data.ProjectDataSet CreateNewProject(string category)
        {
            Data.ProjectDataSet project = new BadHabit.Factory.Data.ProjectDataSet();
            try
            {
                project.Merge(Service.RetriveProjectTemplate(category));
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_CREATE_A_NEW_PROJECT);
            }

            return project;
        }

        public static int NumberOfMemberNeedFor(DateTime startDate, DateTime endDate, double hours)
        {
            int workCount = Data.ProjectDataSet.CalcWorkDayCount(startDate, endDate);
            if (hours == 0)
            {
                return 0;
            }

            return (int)(workCount / hours);
        }

        public static System.Data.DataView UnitList
        {
            get
            {
                ObjectDataProvider ob = Current.Resources["UnitList"] as ObjectDataProvider;
                if (ob == null)
                {
                    return null;
                }

                return ob.ObjectInstance as System.Data.DataView;
            }

            set
            {
                ObjectDataProvider ob = Current.Resources["UnitList"] as ObjectDataProvider;
                ob.ObjectInstance = value;
            }
        }

        public static System.Data.DataView GenericUnitList
        {
            get
            {
                ObjectDataProvider ob = Current.Resources["GenericUnitList"] as ObjectDataProvider;
                if (ob == null)
                {
                    LoadBacklogUnits();
                }

                return ob.ObjectInstance as System.Data.DataView;
            }
        }

        public static System.Data.DataView VisibleBacklogItemList
        {
            get
            {
                ObjectDataProvider ob = Current.Resources["VisibleBacklogItemList"] as ObjectDataProvider;
                if (ob == null)
                {
                    return null;
                }

                return ob.ObjectInstance as System.Data.DataView;
            }

            set
            {
                ObjectDataProvider ob = Current.Resources["VisibleBacklogItemList"] as ObjectDataProvider;
                ob.ObjectInstance = value;
            }
        }

        public static System.Data.DataView ProposalList
        {
            get
            {
                ObjectDataProvider ob = Current.Resources["ProposalList"] as ObjectDataProvider;
                if (ob == null)
                {
                    return null;
                }

                return ob.ObjectInstance as System.Data.DataView;
            }

            set
            {
                ObjectDataProvider ob = Current.Resources["ProposalList"] as ObjectDataProvider;
                ob.ObjectInstance = value;
            }
        }

        public static System.Data.DataView ProjectMemberList
        {
            get
            {
                ObjectDataProvider ob = Current.Resources["ProjectMemberList"] as ObjectDataProvider;
                if (ob == null)
                {
                    return null;
                }

                return ob.ObjectInstance as System.Data.DataView;
            }

            set
            {
                ObjectDataProvider ob = Current.Resources["ProjectMemberList"] as ObjectDataProvider;
                ob.ObjectInstance = value;
            }
        }

        private static bool isShiftingSprints = false;

        public static bool IsUserAtProject
        {
            get
            {
                Data.TeamDataSet.MemberDataTable memberTable = Client.ProjectMemberList.Table as Data.TeamDataSet.MemberDataTable;
                if (memberTable == null)
                {
                    return false;
                }

                Data.TeamDataSet.MemberRow userInProject = memberTable.FindByMemberId(Client.User.Identity.Name);

                return userInProject != null;
            }
        }

        /// <summary>
        /// Returns a DataView with only the assigned members of the project
        /// </summary>
        /// <returns>A TeamDatatable View with the members</returns>
        public static System.Data.DataView GetOnlyRoleMembers(Data.ProjectDataSet project, bool excludeNoMembers)
        {
            // read the project members            
            Data.ProjectDataSet.ProjectRoleDataTable roles = project.ProjectRole;

            Data.TeamDataSet inProjectMembers = new BadHabit.Factory.Data.TeamDataSet();
            inProjectMembers.Merge(Client.TeamMemberDataSet.Member.Select("Disable<>1 or Disable is null"));

            foreach (Data.TeamDataSet.MemberRow member in Client.TeamMemberDataSet.Member.Select("Disable<>1  or Disable is null"))
            {
                Data.ProjectDataSet.ProjectRoleRow[] roleMember = (Data.ProjectDataSet.ProjectRoleRow[])roles.Select("ContactId='" + member.MemberId + "'");
                Data.TeamDataSet.MemberRow memberInProject = inProjectMembers.Member.FindByMemberId(member.MemberId);

                if (roleMember.Length == 0 && excludeNoMembers && !member.MemberId.Equals(String.Empty))
                {
                    memberInProject.Delete();
                }
                else if (roleMember.Length > 0)
                {
                    memberInProject.DefaultUnitName = roleMember[0].UnitName;
                }
            }

            inProjectMembers.Member.DefaultView.Sort = "NickName";

            return inProjectMembers.Member.DefaultView;
        }

        private static bool ShiftSprints(DateTime oldDate, DateTime newDate, Data.ProjectDataSet.SprintRow startSprint)
        {
            bool shouldCancel = false;

            // get the difference in days from the new date
            int diffDays = newDate.Date.Subtract(oldDate.Date).Days;
            if (diffDays == 0)
            {
                return false;
            }

            string message = null;

            // OK WE WILL SHIFT
            isShiftingSprints = true;

            if (diffDays > 0)
            {
                message = global::BadHabit.Factory.Windows.Properties.Resources.Do_you_want_to_shift_forward_the_sprints;

                // check if the new date over laps the next sprint
                // if so, is mandatory to shift the following sprints                
                if (startSprint.ExpirationDate < newDate)
                {
                    message = global::BadHabit.Factory.Windows.Properties.Resources.The_date_informed_overlaps_the_next_sprint_end_date;
                    shouldCancel = true;
                }
            }
            else
            {
                message = global::BadHabit.Factory.Windows.Properties.Resources.Do_you_want_to_shift_back_the_sprints;
            }

            message = string.Format(message, Math.Abs(diffDays));

            MessageBoxResult d = BadHabit.Factory.Views.Error.ShowDialog(message, global::BadHabit.Factory.Windows.Properties.Resources.Shift_Sprints, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes);
            if (d == MessageBoxResult.No)
            {
                isShiftingSprints = false;
                return shouldCancel;
            }

            Data.ProjectDataSet.SprintRow nextSprint = startSprint;
            while (nextSprint != null)
            {
                nextSprint.ExpirationDate = nextSprint.ExpirationDate.AddDays(diffDays);
                nextSprint = nextSprint.NextSprint;
            }

            isShiftingSprints = false;

            return shouldCancel;
        }

        /// <summary>
        /// Shifts the sprints in order to preserve the ahead sprint durations when
        /// a sprint had its expiration date changed.
        /// </summary>
        /// <param name="sprint">The sprint changed</param>
        /// <param name="newDate">The new Expiration date of the sprint changed</param>
        public static bool ShiftSprints(Data.ProjectDataSet.SprintRow sprint, DateTime newDate)
        {
            if (System.Data.DataRowState.Detached.Equals(sprint.RowState) || System.Data.DataRowState.Deleted.Equals(sprint.RowState))
            {
                return false;
            }

            if (isShiftingSprints)
            {
                return false;
            }

            if (sprint == null)
            {
                return false;
            }

            // no sprint ahead to shift
            if (sprint.IsLastSprint)
            {
                return false;
            }

            return ShiftSprints(sprint.ExpirationDate, newDate, sprint.NextSprint);
        }

        /// <summary>
        /// Shifts the sprints in order to preserve the ahead sprint durations when
        /// a sprint had its expiration date changed.
        /// </summary>
        /// <param name="sprint">The sprint changed</param>
        /// <param name="newDate">The new Expiration date of the sprint changed</param>
        public static bool ShiftSprints(Data.ProjectDataSet.ProjectRow project, DateTime newDate)
        {
            if (isShiftingSprints)
            {
                return false;
            }

            if (project == null)
            {
                return false;
            }

            // no sprint ahead to shift
            if (project.GetSprintRows().Length == 0)
            {
                return false;
            }

            return ShiftSprints(project.EstimatedStartDate, newDate, project.FirstSprint);
        }

        public static string SourceControlViewUrl { get; private set; }

        public static Data.TaskDataSet.TaskRow RetriveTask(int taskId)
        {
            Data.TaskDataSet task = new BadHabit.Factory.Data.TaskDataSet();
            try
            {
                task.Merge(Service.RetriveTask(taskId));
            }
            catch (Exception ex)
            {
                BadHabit.Factory.Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_TASKS);
                return null;
            }

            if (task.Task.Count == 0)
            {
                return null;
            }

            return task.Task[0];
        }

        public static bool ShowEditRoleWindow(Data.ProjectDataSet project, bool isCostEdit)
        {
            BadHabit.Factory.Views.EditRoles editRolesWindow = new BadHabit.Factory.Views.EditRoles(isCostEdit);
            editRolesWindow.DataContext = project;

            // THIS IS A WORK AROUND.
            // THE WPF DATAGRID HAS A BUG THAT DOES NOT CATCH THE IEditableObject Exceptions.
            // SO IT IS A PAIN IN THE ASS TO CTACH THE FOREGINKEY CONSTRANTS
            // I WILL WAIT FOR THE NEW VERSION. BY NOW, I USE THIS UGLY CODE
            try
            {
                editRolesWindow.ShowDialog();
            }
            catch (System.Data.InvalidConstraintException)
            {
                BadHabit.Factory.Views.Error.ShowAlert(global::BadHabit.Factory.Windows.Properties.Resources.Is_not_allowed_to_delete_roles);
                project.BacklogItemUnit.RejectChanges();
                editRolesWindow.Close();
                return false;
            }
            catch (System.Data.ConstraintException)
            {
                BadHabit.Factory.Views.Error.ShowAlert(global::BadHabit.Factory.Windows.Properties.Resources.Is_not_allowed_same_short_name_roles);
                project.BacklogItemUnit.RejectChanges();
                editRolesWindow.Close();
                return false;
            }

            return true;
        }
    }
}
